/*
 * SystemException.cpp
 *
 *  Created on: May 8, 2013
 *      Author: Lucifer
 */

#include "pch.h"
#include "SystemException.h"
#ifndef	_WIN32
#include <sys/errno.h>
#endif

namespace BFX
{

/**
 * Creates a new instance with last system error that occurred.
 */
SystemException::SystemException()
	: Exception()
{
	m_nErrorCode = SystemException::GetLastError();
}

/**
 * Creates a new instance with the specified error.
 * @param[in] nErrorCode The error code associated with this exception.
 */
SystemException::SystemException(int nErrorCode)
	: Exception()
{
	m_nErrorCode = nErrorCode;
}

/**
 * Creates a new instance with last system error that occurred.
 * @param[in] pszMessage A detailed description of the error.
 */
SystemException::SystemException(const char* pszMessage)
	: Exception(pszMessage)
{
#ifdef	_WIN32
	m_nErrorCode = (int)::GetLastError();
#else
	m_nErrorCode = errno;
#endif
}

/**
 * Creates a new instance with the specified error.
 * @param[in] nErrorCode The error code associated with this exception.
 * @param[in] pszMessage A detailed description of the error.
 */
SystemException::SystemException(int nErrorCode, const char* pszMessage)
	: Exception(pszMessage)
{
	m_nErrorCode = nErrorCode;
}

/**
 * Copy constructor.
 * @param[in] src The source object copy from.
 */
SystemException::SystemException(const SystemException& src)
	: Exception(src)
{
	m_nErrorCode = src.m_nErrorCode;
}

/**
 * Destroys the instance.
 */
SystemException::~SystemException() throw()
{
}

/**
 * Gets the error code.
 * @return The platform dependent error code.
 */
int SystemException::GetErrorCode() const
{
	return m_nErrorCode;
}

/**
 * Gets a message that describes the current exception.
 * @return
 */
const char* SystemException::GetMessage() const
{
	if (m_strErrorMsg.IsEmpty())
	{
		const char * psz = Exception::GetMessage();
		m_strErrorMsg = psz == NULL ?
				GetErrorMessage(m_nErrorCode) :
				String::Format("%s\n\t%s", psz, (const char*) GetErrorMessage(m_nErrorCode));
	}
	return m_strErrorMsg;
}

/**
 * The static helper to retrieves the calling thread's last system error code value.
 * @return The calling thread's last system error code.
 */
int SystemException::GetLastError()
{
#ifdef	_WIN32
	return (int)::GetLastError();
#else
	return errno;
#endif
}

/**
 * The static helper to translate error code to string.
 * @param[in] nErrorCode
 * @return
 */
String SystemException::GetErrorMessage(int nErrorCode)
{
#ifdef	_WIN32
	SequenceT<char> charBuffer;
	char* pBuffer = charBuffer.GetBuffer(1024);
	DWORD dwMsgLen = ::FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM, NULL, nErrorCode, 0,
			pBuffer, 512, NULL);
	BFX_ENSURE(dwMsgLen > 0);
	return String(pBuffer, dwMsgLen);
#else
	return String(strerror(nErrorCode));
#endif
}

} /* namespace BFX */
